package com.yao.sys.service.impl;

import cn.hutool.core.util.IdcardUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yao.common.bean.LoginUser;
import com.yao.common.constant.SysConst;
import com.yao.common.enums.SysErrorEnum;
import com.yao.common.enums.business.sys.SexEnum;
import com.yao.common.exception.BusinessException;
import com.yao.common.util.RedisUtils;
import com.yao.common.util.ThrowUtils;
import com.yao.common.util.TokenUtils;
import com.yao.sys.entity.dto.UserDto;
import com.yao.sys.entity.dto.UserLoginDto;
import com.yao.sys.entity.dto.UserRoleRelDto;
import com.yao.sys.mapper.UserMapper;
import com.yao.sys.mapper.sql.UserWrapper;
import com.yao.sys.service.UserRoleRelService;
import com.yao.sys.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 用户表 接口实现
 *
 * @author autoCode
 * @version 1.0.0-SNAPSHOT
 * @date 2020-04-09
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, UserDto> implements UserService {

    @Autowired
    private UserRoleRelService userRoleRelService;

    @Override
    public String login(UserLoginDto dto) {

        Wrapper<UserDto> userDtoWrapper = UserWrapper.byName(dto.getUserName(), null);

        UserDto user = this.getOne(userDtoWrapper, true);

        // 对密码加密后校验
        String encryptPwd = SecureUtil.md5(dto.getPassword());

        if (Objects.isNull(user)) {
            throw new BusinessException("用户不存在,请重新输入");
        }

        if (!user.getPassword().equals(encryptPwd)) {
            throw new BusinessException("登陆密码不正确,请重新输入");
        }

        // 创建token
        String token = TokenUtils.create(dto.getUserName());
        user.setAccessToken(token);
        this.updateById(user);

        // 保存token到redis
        LoginUser loginUser = new LoginUser();
        loginUser.setUserId(user.getId());
        loginUser.setUserName(user.getUserName());
        loginUser.setAccessToken(token);
        RedisUtils.set(SysConst.PRE_ACCESS_TOKEN + token, JSON.toJSONString(loginUser));

        return token;

    }

    @Override
    @Transactional(isolation = Isolation.REPEATABLE_READ, rollbackFor = BusinessException.class)
    public void add(UserDto dto) {

        this.checkName(dto);

        dto.setPassword(SecureUtil.md5(dto.getPassword()));
        dto.setSex(this.getSex(dto.getIdCard()));

        if (!this.save(dto)) {
            throw new BusinessException("新增用户失败.");
        }

        // 建立用户-角色关系
        if (StrUtil.isNotBlank(dto.getRoleIds())) {
            UserRoleRelDto userRoleRelDto = new UserRoleRelDto();
            userRoleRelDto.setUserId(dto.getId());
            userRoleRelDto.setRoleIdList(Arrays.stream(dto.getRoleIds().split(",")).map(Integer::parseInt).collect(Collectors.toList()));
            userRoleRelDto.setOperator(dto.getId());
            userRoleRelService.add(userRoleRelDto);
        }


    }

    @Override
    public void modifyById(UserDto dto) {

        this.checkName(dto);

        dto.setPassword(SecureUtil.md5(dto.getPassword()));
        dto.setSex(this.getSex(dto.getIdCard()));

        if (!this.updateById(dto)) {
            throw new BusinessException("更新用户失败.");
        }
    }


    @Override
    public UserDto byId(Integer id) {

        // 用户
        UserDto user = ThrowUtils.isNull(this.getById(id), "id:[{}]查询不到用户.", id);

        // 用户-角色关系
        LambdaQueryWrapper<UserRoleRelDto> relQuery = Wrappers.lambdaQuery();
        relQuery.eq(UserRoleRelDto::getUserId, id);
        String roleIds = userRoleRelService.list(relQuery).stream().map(UserRoleRelDto::getRoleId).map(Objects::toString).collect(Collectors.joining(","));
        user.setRoleIds(roleIds);

        return user;
    }

    private void checkName(UserDto dto) {
        Wrapper<UserDto> query = UserWrapper.byName(dto.getUserName(), dto.getId());
        UserDto user = this.getOne(query);

        if (Objects.nonNull(user)) {
            throw new BusinessException("用户名:[{}]重复.", dto.getUserName());
        }
    }

    /**
     * 获取性别 男：奇数 女：偶数
     * 
     * @param idcard
     *            身份证号
     * @author yaoyuming
     * @date 2020/7/12
     * @return {@link com.yao.common.enums.business.sys.SexEnum}
     */
    private SexEnum getSex(String idcard) {
        if (StrUtil.isBlank(idcard)) {
            return null;
        }
        int gender = IdcardUtil.getGenderByIdCard(idcard);

        return gender == 1 ? SexEnum.MALE : SexEnum.FEMALE;
    }

    @Override
    public UserDto checkUser(Integer id) {
        if (null == id) {
            throw new BusinessException(SysErrorEnum.PARAMETER_ERROR);
        }

        return Optional.ofNullable(this.getById(id)).orElseThrow(() -> new BusinessException("用户[{}]不存在", id));
    }
}